<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Document</title>

</head>
<body onload="main(document.getElementById('graphContainer'))">
<div id="graphContainer">

</div>
</body>
</html>
<script type="text/javascript">
    var mxBasePath = "./mx-graph/src/";

</script>
<script src="./mx-graph/src/js/mxClient.js"></script>

<script type="text/javascript">
    // Program starts here. Creates a sample graph in the
    // DOM node with the specified ID. This function is invoked
    // from the onLoad event handler of the document (see below).
    function main(container) {
        // Checks if the browser is supported
        if (!mxClient.isBrowserSupported()) {
            // Displays an error message if the browser is not supported.
            mxUtils.error('Browser is not supported!', 200, false);
        } else {
            mxEvent.disableContextMenu(container);

            var mxCellRendererInstallCellOverlayListeners = mxCellRenderer.prototype.installCellOverlayListeners;
            mxCellRenderer.prototype.installCellOverlayListeners = function (state, overlay, shape) {
                mxCellRendererInstallCellOverlayListeners.apply(this, arguments);

                mxEvent.addListener(shape.node, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', function (evt) {
                    overlay.fireEvent(new mxEventObject('pointerdown', 'event', evt, 'state', state));
                });

                if (!mxClient.IS_POINTER && mxClient.IS_TOUCH) {
                    mxEvent.addListener(shape.node, 'touchstart', function (evt) {
                        overlay.fireEvent(new mxEventObject('pointerdown', 'event', evt, 'state', state));
                    });
                }
            };

            // Creates the graph inside the given container
            var graph = new mxGraph(container);
            graph.setPanning(true);
            graph.panningHandler.useLeftButtonForPanning = true;
            graph.setAllowDanglingEdges(false);
            graph.connectionHandler.select = false;
            graph.view.setTranslate(20, 20);

            // Enables rubberband selection
            new mxRubberband(graph);

            // Gets the default parent for inserting new cells. This
            // is normally the first child of the root (ie. layer 0).
            var parent = graph.getDefaultParent();

            var addOverlay = function (cell) {
                // Creates a new overlay with an image and a tooltip
                var overlay = new mxCellOverlay(new mxImage(mxBasePath + '/image/add.png', 24, 24), 'Add outgoing');
                overlay.cursor = 'hand';

                // Installs a handler for clicks on the overlay
                overlay.addListener(mxEvent.CLICK, function (sender, evt2) {
                    graph.clearSelection();
                    var geo = graph.getCellGeometry(cell);

                    var v2;
                   

                    executeLayout(function () {
                        console.log(cell)
                        v2 = graph.insertVertex(parent, null, cell.id+"-hello", geo.x, geo.y, 80, 30);
                        addOverlay(v2);
                        graph.view.refresh(v2);
                        var e1 = graph.insertEdge(parent, null, '', cell, v2);
                    }, function () {
                        graph.scrollCellToVisible(v2);
                    });
                });

                // Special CMS event
                overlay.addListener('pointerdown', function (sender, eo) {
                    var evt2 = eo.getProperty('event');
                    var state = eo.getProperty('state');

                    graph.popupMenuHandler.hideMenu();
                    graph.stopEditing(false);

                    var pt = mxUtils.convertPoint(graph.container,
                        mxEvent.getClientX(evt2), mxEvent.getClientY(evt2));
                    graph.connectionHandler.start(state, pt.x, pt.y);
                    graph.isMouseDown = true;
                    graph.isMouseTrigger = mxEvent.isMouseEvent(evt2);
                    mxEvent.consume(evt2);
                });

                // Sets the overlay for the cell in the graph
                graph.addCellOverlay(cell, overlay);
            }

            // Adds cells to the model in a single step
            graph.getModel().beginUpdate();
            var v1;
            try {
                v1 = graph.insertVertex(parent, null, 'Hello,', 0, 0, 80, 30);
                addOverlay(v1);
            } finally {
                // Updates the display
                graph.getModel().endUpdate();
            }

            var layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_WEST);

           var executeLayout = function (change, post) {
                // 开始更新模型
                graph.getModel().beginUpdate();
                try {
                    // 如果存在改变函数，则执行改变函数
                    if (change != null) {
                        change();
                    }

                    // 执行布局
                    layout.execute(graph.getDefaultParent(), v1);
                } catch (e) {
                    throw e;
                } finally {
                    // New API for animating graph layout results asynchronously
                    // 新的API异步执行布局结果
                    var morph = new mxMorphing(graph);
                    morph.addListener(mxEvent.DONE, mxUtils.bind(this, function () {
                        // 结束更新模型
                        graph.getModel().endUpdate();

                        // 如果存在post函数，则执行post函数
                        if (post != null) {
                            post();
                        }
                    }));

                    // 开始动画
                    morph.startAnimation();
                }
            };

            // 重新定义连接函数，在连接函数中执行布局
            var edgeHandleConnect = mxEdgeHandler.prototype.connect;
            mxEdgeHandler.prototype.connect = function (edge, terminal, isSource, isClone, me) {
                edgeHandleConnect.apply(this, arguments);
                executeLayout();
            };

            // 重新定义resizeCell函数，在resizeCell函数中执行布局
            graph.resizeCell = function () {
                mxGraph.prototype.resizeCell.apply(this, arguments);

                executeLayout();
            };

            // 添加连接事件监听器，在连接事件中执行布局
            graph.connectionHandler.addListener(mxEvent.CONNECT, function () {
                executeLayout();
            });
        }
    };
</script>
<style>
    *{
        margin: 0;
        padding: 0;
    }
    #graphContainer {
        position: relative;
        overflow: hidden;
        width: 100vw;
        height: 100vh;
        background: url('mx-graph/examples/editors/images/grid.gif');
        cursor: default;
    }


</style>
